-
Notifications
You must be signed in to change notification settings - Fork 94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement command line parser builtin #663
base: staging
Are you sure you want to change the base?
Conversation
@@ -70,6 +71,7 @@ struct RunCommand { | |||
|
|||
/// Arguments passed to Amber script | |||
#[arg(trailing_var_arg = true)] | |||
#[arg(allow_hyphen_values = true)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This allows long options --xyz
and short options -x
to be passed to the Amber script, without being rejected as invalid by the clap
library; but clap
still consumes the --help
option with amber script.ab --help
or ./script.ab --help
. I would like to make it pass all options following a positional argument to the Amber script, but I'm not sure how. All suggestions appreciated!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is of course possible to force options to be passed to the script with amber script.ab -- --help
. I've tried moving this Clap argument to the end of the struct and adding #[arg(last = true)]
, but that makes it necessary to call amber script.ab -- arg1 arg2
for all arguments, not just --help
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hdwalters does allow_external_subcommands
solve this issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure it would. According to the docs, it handles "unexpected positional arguments" (such as foo
) not optional ones (such as --help
).
I will try it, however.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may have to put up with ./script.ab -- --help
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah... I think that this solution of adding the --
is good enough. It adds the separation between the Amber's arguments and the script args.
src/modules/builtin/cli/param.rs
Outdated
|
||
impl ParamKind { | ||
fn from(option: String) -> Option<Self> { | ||
let regex = regex!(r"^(?:(\w+)|-(\w)|--(\w+))$"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The regular expression is only compiled once; see definition of the regex
macro, which uses the once_cell
crate to do cached lazy evaluation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May be worth supporting long options with hyphens in the name, like --no-foo
. If so, will need to modify the regular expression.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now supports --no-foo
, but not ---no-foo
, --no--foo
or --no-foo-
.
} | ||
|
||
impl ParamCli { | ||
pub fn get_payload(&self) -> Option<Payload> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this PR, we introduce the new concept of a "payload", which can be attached to a variable declaration. This allows us to store reference counted CLI parameter data in this struct (where it provides type information for variable getters) and in the parser struct (where it provides parameter information for the help text and command line parsing code).
} | ||
|
||
impl Typed for ParamCli { | ||
fn get_type(&self) -> Type { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expose the type of the default value, e.g. Text
, [Text]
, Num
, Bool
etc, to variable getters, so we can get the values of parameter objects in the same way as ordinary variables.
Some(parser) => parser, | ||
None => return error!(meta, parser_tok, "Expected parser object"), | ||
}; | ||
let option = match option.get_literal_text() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The option text, e.g. -x|--xyz
, and help text need to be known at compile time, so they can be baked into the case
statement and help information in the translated parser code.
} | ||
} | ||
|
||
fn create_run_name(meta: &TranslateMetadata, args: &Expr) -> String { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Returns the compile time Amber script name if run with amber run
or shebang, or the run time Bash script name if built with amber build
.
@@ -11,6 +11,16 @@ pub struct Text { | |||
interps: Vec<Expr>, | |||
} | |||
|
|||
impl Text { | |||
pub fn get_literal_text(&self) -> Option<String> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Returns the literal text if compiled from "literal text"
and not "interpolated {foo} text"
.
self.is_const, | ||
); | ||
if let Some(mut payload) = self.expr.get_payload() { | ||
payload.set_var_name(&self.name, self.global_id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Parameter payloads require the original variable name, so it can be baked into the translated parser code.
.join("\n") | ||
} | ||
|
||
fn trim_comment(line: &str) -> &str { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to be a bit cleverer about trimming expected output text, because the CLI parser validity tests need to check for CLI help text with leading whitespace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i like how this is implemented, but i'd like to talk about the feature itself in the issue
Fixes #613.